// to compile: g++ -I/opt/local/include -L/opt/local/lib -lboost_thread-mt test-interrupt-thread.cpp

#include <iostream>
#include <vector>

#include <boost/thread.hpp>  
#include <boost/date_time.hpp>  
#include <boost/shared_ptr.hpp>

class Slave
{
public:
  Slave(int i_)
    : i(i_)
  { }

  void
  work()
  {
    boost::posix_time::seconds one_sec(1);
    j = 0;
    
    while (j < i)
      {
	++j;
	std::cout << "Slave(" << i << "): running at position " << j << std::endl;
	boost::this_thread::interruption_point();
	boost::this_thread::sleep(one_sec);
      }
    std::cout << "Slave(" << i << "): finished" << std::endl;    
  }

public:
  int i;
  int j;
};


class Worker
{
public:
  Worker(int i_)
    : slave(i_)
  { }

  void operator()()
  {
    try
      {
	slave.work();
      }
    catch (const boost::thread_interrupted& ex)
      {
	std::cerr << "Slave " << slave.i << " was interrupted at position " << slave.j << std::endl;
      }
  }

private:
  Slave slave;
};


typedef boost::shared_ptr<Worker> WorkerPtr;
typedef std::vector<boost::thread*> ThreadVec;

int main()
{
  ThreadVec tv;

  std::cout << "main: startup" << std::endl;

  for (int i = 4; i > 0; --i)
    {
      Worker wi(i);
      
      boost::thread* workerThread = new boost::thread(wi);
      tv.push_back(workerThread);
    }
  
  std::cout << "all started" << std::endl;

  // let Slave(2) work a bit before we interrupt it
  sleep(2);
  ThreadVec::iterator it = tv.begin();
  it++;
  it++;
  (*it)->interrupt();

      
  for (ThreadVec::iterator it = tv.begin(); it != tv.end(); ++it)
    {
      (*it)->join();
    }

  std::cout << "main: done" << std::endl;
}
